package com.genexususa.eo.google.connection;

import com.genexususa.eo.google.data.*;
import com.genexususa.eo.google.test.Constants;
import com.google.api.ads.adwords.axis.v201406.cm.*;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;


public class CampaignCriterionManager {


    private static final int PAGE_SIZE = 5000;
    private String _clientId;

    public void SetClientId(String clientId) {
        this._clientId = clientId;
    }

    public String GetClientId() {
        return _clientId;
    }

    public void Finalize() {

        SessionController sc = SessionController.getInstance();
        sc.RemoveSession(_clientId);
    }


    public String CreateCampaignCriterion(String xml) {

        try {

            String result = "";

            // Get the instance of service's factory
            ServiceFactory sf = ServiceFactory.getInstance();

            // Get Campaign Criterion Service
            CampaignCriterionServiceInterface campaignCriterionService = sf.GetCampaignCriterionService(this.GetClientId());

            //GA_ResultCreateCriterion res = new GA_ResultCreateCriterion();
            GA_Result res = new GA_Result();


            Util util = new Util();

            Document doc = util.loadXMLFromString(xml);

            XPathFactory factory = XPathFactory.newInstance();
            XPath xpath = factory.newXPath();

            XPathExpression expr = xpath.compile("//GA_Criterion");

            Object criterionNodes = expr.evaluate(doc, XPathConstants.NODESET);

            NodeList criterions = (NodeList) criterionNodes;

            ArrayList<GA_ResultItem> campaignCriterions = new ArrayList<GA_ResultItem>();

            if (criterions.getLength() > 0) {

                for (int i = 0; i < criterions.getLength(); i++) { // For all GA_Criterion Nodes

                    Node n = criterions.item(i);

                    NodeList children = n.getChildNodes();

                    //GA_Criterion criterion = new GA_Criterion();

                    GA_ResultItem criterion = new GA_ResultItem();

                    Double bidModifier = null;
                    boolean isNegative = false;

                    Criterion adwordsCriterion = null;

                    for (int j = 0; j < children.getLength(); j++) {

                        if (children.item(j).getNodeName().equalsIgnoreCase("CampaignGxId")) {
                            criterion.SubCampaignGxId = Long.parseLong(children.item(j).getTextContent());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("AdGroupGxId")) {
                            criterion.AdGroupGxId = Long.parseLong(children.item(j).getTextContent());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("CriterionGxId")) {
                            criterion.CriterionGxId = Long.parseLong(children.item(j).getTextContent());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("CampaignID")) {
                            criterion.CampaignId = Long.parseLong(children.item(j).getTextContent());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("CriterionUse")) {
                            isNegative = Util.criterionUseFromString(children.item(j).getTextContent()).equals(CriterionUse.NEGATIVE);
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("Keyword")) {
                            adwordsCriterion = GetKeywordCriterion(children.item(j).getChildNodes());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("IpBlock")) {
                            adwordsCriterion = GetIpBlockCriterion(children.item(j).getChildNodes());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("AdSchedule")) {
                            adwordsCriterion = GetAdScheduleCriterion(children.item(j).getChildNodes());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("Location")) {
                                adwordsCriterion = GetLocationCriterion(children.item(j).getChildNodes());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("bidModifier")) {
                            if (!children.item(j).getTextContent().equalsIgnoreCase("")) {
                                bidModifier = Double.parseDouble(children.item(j).getTextContent());
                            }
                        }
                    }
                    if (adwordsCriterion != null) {
                        if (isNegative) {
                            criterion.CampaignCriterion = new NegativeCampaignCriterion();
                        } else {
                            criterion.CampaignCriterion = new CampaignCriterion();
                        }
                        criterion.CampaignCriterion.setCriterion(adwordsCriterion);

                        if (bidModifier != null) {
                            criterion.CampaignCriterion.setBidModifier(bidModifier);
                        }
                        if (criterion.CampaignId != null) {
                            criterion.CampaignCriterion.setCampaignId(criterion.CampaignId);
                        }
                    }
                    campaignCriterions.add(criterion);
                }
                ArrayList<GA_ResultItem> createdCriterions = new ArrayList<GA_ResultItem>();
                ArrayList<CampaignCriterionOperation> ops = new ArrayList<CampaignCriterionOperation>();
                for (GA_ResultItem kw : campaignCriterions) {
                    CampaignCriterionOperation operation = new CampaignCriterionOperation();
                    operation.setOperand(kw.CampaignCriterion);
                    operation.setOperator(Operator.ADD);
                    ops.add(operation);
                }

                CampaignCriterionOperation[] opsArray = new CampaignCriterionOperation[]{};

                CampaignCriterionOperation[] operations = ops.toArray(opsArray);


                CampaignCriterionReturnValue returnValue = campaignCriterionService.mutate(operations);

                Thread.sleep(1000);

                int j = 0;

                for (int i = 0; i < returnValue.getValue().length; i++) {


                    GA_ResultItem created = new GA_ResultItem();

                    created.AdGroupGxId = campaignCriterions.get(i).AdGroupGxId;
                    created.AdGroupId = campaignCriterions.get(i).AdGroupId;
                    created.SubCampaignGxId = campaignCriterions.get(i).SubCampaignGxId;
                    created.CampaignId = campaignCriterions.get(i).CampaignId;
                    created.CriterionGxId = campaignCriterions.get(i).CriterionGxId;

                    if (returnValue.getValue(i).getCriterion() == null) {

                        created.CriterionId = 0L;
                        created.HasError = true;

                        ErrorsStruct errors = new ErrorsStruct();

                        errors.Message = returnValue.getPartialFailureErrors(j).getErrorString();

                        errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

                        com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

                        err.ErrorString = returnValue.getPartialFailureErrors(j).getErrorString();
                        err.fieldPath = returnValue.getPartialFailureErrors(j).getFieldPath();
                        //err.Reason = returnValue.getPartialFailureErrors(i). .getFaultReason();
                        err.Trigger = returnValue.getPartialFailureErrors(j).getTrigger();
                        err.Type = returnValue.getPartialFailureErrors(j).getApiErrorType();

                        j++;

                        errors.Errors.add(err);

                        created.Errors = errors;

                        createdCriterions.add(created);

                    } else {
                        created.CriterionId = returnValue.getValue(i).getCriterion().getId();

                        createdCriterions.add(created);
                    }
                }


                try {

                JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                Marshaller marshallerObj = contextObj.createMarshaller();
                marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                StringWriter sw = new StringWriter();

                res.Items = createdCriterions;

                marshallerObj.marshal(res, sw);
                result = sw.getBuffer().toString();

                System.out.println(result);

            } catch (Exception exc) {
                exc.printStackTrace();
                result = exc.getMessage();

            }
        }


        return result;

        } catch (Exception exc) {

            GA_Result res = new GA_Result();

            ArrayList<GA_ResultItem> items = new ArrayList<GA_ResultItem>();

            GA_ResultItem error = new GA_ResultItem();

            ErrorsStruct errors = new ErrorsStruct();

            errors.Message = exc.getMessage();

            errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

            com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

            StringWriter st = new StringWriter();
            exc.printStackTrace(new PrintWriter(st));

            err.UnknownError = st.toString();

            errors.Errors.add(err);

            error.Errors = errors;

            error.HasError = true;

            items.add(error);

            String result = "";

            try {

                JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                Marshaller marshallerObj = contextObj.createMarshaller();
                marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                StringWriter sw = new StringWriter();

                res.Items = items;

                marshallerObj.marshal(res, sw);
                result = sw.getBuffer().toString();
                System.out.println(result);
                return result;

            } catch (Exception ex) {
                ex.printStackTrace();
                result = ex.getMessage();
                return result;
            }
        }
    }

    public String DeleteCampaignCriterion(Long campaignId, Long criterionId) {

        try {

            String result = "";

            GA_Result res = new GA_Result();

            // Get the instance of service's factory
            ServiceFactory sf = ServiceFactory.getInstance();

            // Get Campaign Criterion Service
            CampaignCriterionServiceInterface campaignCriterionService = sf.GetCampaignCriterionService(this.GetClientId());

            Criterion criterion = new Criterion();
            criterion.setId(criterionId);

            CampaignCriterion campaignCriterion = new CampaignCriterion();
            campaignCriterion.setCriterion(criterion);
            campaignCriterion.setCampaignId(campaignId);


            CampaignCriterionOperation operation = new CampaignCriterionOperation();
            operation.setOperand(campaignCriterion);
            operation.setOperator(Operator.REMOVE);


            GA_ResultItem deleted = new GA_ResultItem();
            deleted.CampaignId = campaignId;
            deleted.CriterionId = criterionId;


            try {
                CampaignCriterionOperation[] operations = new CampaignCriterionOperation[]{operation};

                CampaignCriterionReturnValue returnValue = campaignCriterionService.mutate(operations);

                Thread.sleep(1000);

                res.Items.add(deleted);

            } catch (ApiException apiException) {

                boolean retry = false;

                ApiError[] apiErrors = apiException.getErrors();

                for (ApiError error : apiErrors) {

                    if (error.getErrorString().equalsIgnoreCase("RateExceededError.RATE_EXCEEDED")) {

                        Thread.sleep(35000);


                        operation = new CampaignCriterionOperation();
                        operation.setOperand(campaignCriterion);
                        operation.setOperator(Operator.ADD);

                        CampaignCriterionOperation[] operations = new CampaignCriterionOperation[]{operation};

                        CampaignCriterionReturnValue returnValue = campaignCriterionService.mutate(operations);

                        Thread.sleep(1000);

                        deleted.CriterionId = returnValue.getValue(0).getCriterion().getId();

                        res.Items.add(deleted);

                        retry = true;

                    }


                }


                if (!retry) {

                    deleted.CriterionId = 0L;
                    deleted.HasError = true;

                    for (ApiError apiError : apiErrors) {
                        ErrorsStruct errors = new ErrorsStruct();

                        errors.Message = apiError.getErrorString();

                        errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

                        com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

                        err.ErrorString = apiError.getErrorString();
                        err.fieldPath = apiError.getFieldPath();
                        err.Reason = apiException.getFaultReason();
                        err.Trigger = apiError.getTrigger();
                        err.Type = apiError.getApiErrorType();

                        errors.Errors.add(err);

                        deleted.Errors = errors;

                        res.Items.add(deleted);
                    }
                }

            }


            try {

                JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                Marshaller marshallerObj = contextObj.createMarshaller();
                marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                StringWriter sw = new StringWriter();

                //res.Items = res.Items;

                marshallerObj.marshal(res, sw);
                result = sw.getBuffer().toString();

                System.out.println(result);

            } catch (Exception exc) {
                exc.printStackTrace();
                result = exc.getMessage();

            }

            return result;

        } catch (Exception exc) {

            GA_Result res = new GA_Result();

            ArrayList<GA_ResultItem> items = new ArrayList<GA_ResultItem>();

            GA_ResultItem error = new GA_ResultItem();

            ErrorsStruct errors = new ErrorsStruct();

            errors.Message = exc.getMessage();

            errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

            com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

            StringWriter st = new StringWriter();
            exc.printStackTrace(new PrintWriter(st));

            err.UnknownError = st.toString();

            errors.Errors.add(err);

            error.Errors = errors;

            error.HasError = true;

            items.add(error);

            String result = "";

            try {

                JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                Marshaller marshallerObj = contextObj.createMarshaller();
                marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                StringWriter sw = new StringWriter();

                res.Items = items;

                marshallerObj.marshal(res, sw);
                result = sw.getBuffer().toString();
                System.out.println(result);
                return result;

            } catch (Exception ex) {
                ex.printStackTrace();
                result = ex.getMessage();
                return result;
            }
        }

    }

    public String CreateCampaignProximityCriterion(String xml){

         try{

             String result = "";

             // Get the instance of service's factory
             ServiceFactory sf = ServiceFactory.getInstance();

             // Get Campaign Criterion Service
             CampaignCriterionServiceInterface campaignCriterionService = sf.GetCampaignCriterionService(this.GetClientId());

             GA_Result res = new GA_Result();


             Util util = new Util();

             Document doc = util.loadXMLFromString(xml);

             XPathFactory factory = XPathFactory.newInstance();
             XPath xpath = factory.newXPath();

             XPathExpression expr = xpath.compile("//GA_CampaignLocation");

             Object proximityNodes = expr.evaluate(doc, XPathConstants.NODESET);

             NodeList proximities = (NodeList) proximityNodes;

             ArrayList<GA_ResultItem> campaignCriterions = new ArrayList<GA_ResultItem>();

             if (proximities.getLength() > 0){

                 for (int i = 0; i < proximities.getLength(); i++) { // For all GA_CampaignLocation Nodes

                     Node n = proximities.item(i);

                     NodeList children = n.getChildNodes();

                     GA_ResultItem proximityItem = new GA_ResultItem();

                     Proximity proximity = new Proximity();

                     GeoPoint geoPoint = new GeoPoint();

                     Double radius = null;

                     Address address = null;

                     boolean withGeoPoint = false;

                     for (int j = 0; j < children.getLength(); j++) {

                         if (children.item(j).getNodeName().equalsIgnoreCase("CampaignGxId")) {
                             proximityItem.SubCampaignGxId = Long.parseLong(children.item(j).getTextContent());
                         }

                         if (children.item(j).getNodeName().equalsIgnoreCase("CampaignID")) {
                             proximityItem.CampaignId = Long.parseLong(children.item(j).getTextContent());
                         }

                         if (children.item(j).getNodeName().equalsIgnoreCase("Latitude")) {
                             geoPoint.setLatitudeInMicroDegrees(Integer.parseInt(children.item(j).getTextContent()));
                             withGeoPoint = true;
                         }

                         if (children.item(j).getNodeName().equalsIgnoreCase("Longitude")) {
                             geoPoint.setLongitudeInMicroDegrees(Integer.parseInt(children.item(j).getTextContent()));
                             withGeoPoint = true;
                         }

                         if (children.item(j).getNodeName().equalsIgnoreCase("Radius")) {
                             radius = new Double(children.item(j).getTextContent());
                         }

                         if (children.item(j).getNodeName().equalsIgnoreCase("Address")){
                             address = GetProximityAddress(children.item(j).getChildNodes());
                         }


                         if (children.item(j).getNodeName().equalsIgnoreCase("ProximityGxId")){
                             proximityItem.ProximityGxId = Long.parseLong(children.item(j).getTextContent());
                         }
                     }

                     if (withGeoPoint)
                        proximity.setGeoPoint(geoPoint);

                     proximity.setRadiusInUnits(radius);
                     proximity.setRadiusDistanceUnits(ProximityDistanceUnits.MILES);

                     if (address != null){
                         proximity.setAddress(address);
                     }

                     proximityItem.Proximity = proximity;

                     campaignCriterions.add(proximityItem);


                 }

                 ArrayList<GA_ResultItem> createdProximities = new ArrayList<GA_ResultItem>();

                 ArrayList<CampaignCriterionOperation> ops = new ArrayList<CampaignCriterionOperation>();

                 for (GA_ResultItem p : campaignCriterions) {


                     CampaignCriterionOperation operation = new CampaignCriterionOperation();

                     CampaignCriterion campaignCriterion = new CampaignCriterion();
                     campaignCriterion.setCampaignId(p.CampaignId);
                     campaignCriterion.setCriterion(p.Proximity);

                     operation.setOperand(campaignCriterion);
                     operation.setOperator(Operator.ADD);


                     ops.add(operation);
                 }

                 CampaignCriterionOperation[] opsArray = new CampaignCriterionOperation[]{};

                 CampaignCriterionOperation[] operations = ops.toArray(opsArray);


                 CampaignCriterionReturnValue returnValue = campaignCriterionService.mutate(operations);

                 Thread.sleep(1000);

                 int j = 0;

                 for (int i = 0; i < returnValue.getValue().length; i++) {


                     GA_ResultItem created = new GA_ResultItem();

                     created.SubCampaignGxId = campaignCriterions.get(i).SubCampaignGxId;
                     created.CampaignId = campaignCriterions.get(i).CampaignId;
                     created.ProximityGxId = campaignCriterions.get(i).ProximityGxId;


                     if (returnValue.getValue(i).getCriterion() == null) {

                         created.ProximityId = 0L;
                         created.HasError = true;

                         ErrorsStruct errors = new ErrorsStruct();

                         errors.Message = returnValue.getPartialFailureErrors(j).getErrorString();

                         errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

                         com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

                         err.ErrorString = returnValue.getPartialFailureErrors(j).getErrorString();
                         err.fieldPath = returnValue.getPartialFailureErrors(j).getFieldPath();
                         //err.Reason = returnValue.getPartialFailureErrors(i). .getFaultReason();
                         err.Trigger = returnValue.getPartialFailureErrors(j).getTrigger();
                         err.Type = returnValue.getPartialFailureErrors(j).getApiErrorType();

                         j++;

                         errors.Errors.add(err);

                         created.Errors = errors;

                         createdProximities.add(created);

                     } else {
                         created.ProximityId = returnValue.getValue(i).getCriterion().getId();

                         createdProximities.add(created);
                     }
                 }


                 try {

                     JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                     Marshaller marshallerObj = contextObj.createMarshaller();
                     marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                     StringWriter sw = new StringWriter();

                     res.Items = createdProximities;

                     marshallerObj.marshal(res, sw);
                     result = sw.getBuffer().toString();

                     System.out.println(result);

                 } catch (Exception exc) {
                     exc.printStackTrace();
                     result = exc.getMessage();

                 }
             }


             return result;



         } catch (Exception exc) {

             GA_Result res = new GA_Result();

             ArrayList<GA_ResultItem> items = new ArrayList<GA_ResultItem>();

             GA_ResultItem error = new GA_ResultItem();

             ErrorsStruct errors = new ErrorsStruct();

             errors.Message = exc.getMessage();

             errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

             com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

             StringWriter st = new StringWriter();
             exc.printStackTrace(new PrintWriter(st));

             err.UnknownError = st.toString();

             errors.Errors.add(err);

             error.Errors = errors;

             error.HasError = true;

             items.add(error);

             String result = "";

             try {

                 JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                 Marshaller marshallerObj = contextObj.createMarshaller();
                 marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                 StringWriter sw = new StringWriter();

                 res.Items = items;

                 marshallerObj.marshal(res, sw);
                 result = sw.getBuffer().toString();
                 System.out.println(result);
                 return result;

             } catch (Exception ex) {
                 ex.printStackTrace();
                 result = ex.getMessage();
                 return result;
             }
         }



    }

    private Address GetProximityAddress(NodeList childNodes) {

        Address result = new Address();

        for (int i = 0; i < childNodes.getLength(); i++){

            if (childNodes.item(i).getNodeName().equalsIgnoreCase("StreetAddress")) {
                if (childNodes.item(i).getTextContent() != null && !childNodes.item(i).getTextContent().equalsIgnoreCase(""))
                    result.setStreetAddress(childNodes.item(i).getTextContent());
            }

            if (childNodes.item(i).getNodeName().equalsIgnoreCase("StreetAddress2")) {

                if (childNodes.item(i).getTextContent() != null && !childNodes.item(i).getTextContent().equalsIgnoreCase(""))
                    result.setStreetAddress2(childNodes.item(i).getTextContent());
            }

            if (childNodes.item(i).getNodeName().equalsIgnoreCase("CityName")) {
                if (childNodes.item(i).getTextContent() != null && !childNodes.item(i).getTextContent().equalsIgnoreCase(""))
                    result.setCityName(childNodes.item(i).getTextContent());
            }

            if (childNodes.item(i).getNodeName().equalsIgnoreCase("ProvidenceName")) {
                result.setProvinceName(childNodes.item(i).getTextContent());
            }

            if (childNodes.item(i).getNodeName().equalsIgnoreCase("ProvidenceCode")) {
                result.setProvinceCode(childNodes.item(i).getTextContent());
            }

            if (childNodes.item(i).getNodeName().equalsIgnoreCase("PostalCode")) {
                if (childNodes.item(i).getTextContent() != null && !childNodes.item(i).getTextContent().equalsIgnoreCase(""))
                    result.setPostalCode(childNodes.item(i).getTextContent());
            }

            if (childNodes.item(i).getNodeName().equalsIgnoreCase("CountryCode")) {
                result.setCountryCode(childNodes.item(i).getTextContent());
            }

        }
        return result;
    }


    private Criterion GetKeywordCriterion(NodeList children) {

        Keyword keyword = new Keyword();

        for (int i = 0; i < children.getLength(); i++) {

            if (children.item(i).getNodeName().equalsIgnoreCase("Text")) {

                keyword.setText(children.item(i).getTextContent());
            }

            if (children.item(i).getNodeName().equalsIgnoreCase("MatchType")) {

                if (children.item(i).getTextContent().equalsIgnoreCase("E")) {
                    keyword.setMatchType(KeywordMatchType.EXACT);
                } else if (children.item(i).getTextContent().equalsIgnoreCase("P")) {
                    keyword.setMatchType(KeywordMatchType.PHRASE);
                } else if (children.item(i).getTextContent().equalsIgnoreCase("B")) {
                    keyword.setMatchType(KeywordMatchType.BROAD);
                }
            }

        }


        return keyword;
    }

    private IpBlock GetIpBlockCriterion(NodeList children) {
        IpBlock ipBlock = new IpBlock();
        for (int i = 0; i < children.getLength(); i++) {
            if (children.item(i).getNodeName().equalsIgnoreCase("IpAddress")) {
                ipBlock.setIpAddress(children.item(i).getTextContent());
            }
        }
        return ipBlock;
    }

    private AdSchedule GetAdScheduleCriterion(NodeList children) {
        AdSchedule adSchedule = new AdSchedule();
        for (int i = 0; i < children.getLength(); i++) {
            if (children.item(i).getNodeName().equalsIgnoreCase("DayOfWeek")) {
                adSchedule.setDayOfWeek(Util.dayOfWeekFromString(children.item(i).getTextContent()));
            }
            if (children.item(i).getNodeName().equalsIgnoreCase("StartHour")) {
                adSchedule.setStartHour(Integer.valueOf(children.item(i).getTextContent()));
            }
            if (children.item(i).getNodeName().equalsIgnoreCase("StartMinute")) {
                adSchedule.setStartMinute(Util.minuteOfHourFromString(children.item(i).getTextContent()));
            }
            if (children.item(i).getNodeName().equalsIgnoreCase("EndHour")) {
                adSchedule.setEndHour(Integer.valueOf(children.item(i).getTextContent()));
            }
            if (children.item(i).getNodeName().equalsIgnoreCase("EndMinute")) {
                adSchedule.setEndMinute(Util.minuteOfHourFromString(children.item(i).getTextContent()));
            }
        }
        return adSchedule;
    }

    private Location GetLocationCriterion(NodeList children) {
        Location location = new Location();
        String locationName = null;
        String displayType = null;
        for (int i = 0; i < children.getLength(); i++) {
            if (children.item(i).getNodeName().equalsIgnoreCase("LocationName")) {
                locationName = children.item(i).getTextContent();
            }
            if (children.item(i).getNodeName().equalsIgnoreCase("DisplayType")) {
                displayType = children.item(i).getTextContent();
            }
        }
        if (locationName != null && displayType != null) {
            LocationCriterionManager lcm = new LocationCriterionManager();
            lcm.SetClientId(this.GetClientId());
            LocationCriterion locationCriterion = lcm.getLocationFromName(displayType, locationName);
            if (locationCriterion != null) {
                location.setId(locationCriterion.getLocation().getId());
            }
        }
        return location;
    }

    protected ArrayList<ProximityReport> GetProximities(String clientId){
        ArrayList<ProximityReport> result = new ArrayList<ProximityReport>();

        // Get the instance of service's factory
        ServiceFactory sf = ServiceFactory.getInstance();

        try {
            // Get Campaign Criterion Service
            CampaignCriterionServiceInterface campaignCriterionService = sf.GetCampaignCriterionService(clientId);

            int offset = 0;
            Selector selector = new Selector();

            selector.setPaging(new Paging(offset, PAGE_SIZE));
            //selector.setOrdering(new OrderBy[] {new OrderBy("Name", SortOrder.ASCENDING)});

            selector.setFields(new String[]{
                    "Address",
                    "GeoPoint",
                    "Id",
                    "RadiusDistanceUnits",
                    "RadiusInUnits"
            });

            // Create predicates.
            Predicate criterionTypePredicate =
                    new Predicate("CriteriaType", PredicateOperator.EQUALS, new String[]{"PROXIMITY"});
            selector.setPredicates(new Predicate[]{criterionTypePredicate});

            CampaignCriterionPage page = null;

            try {
                do {
                    page = campaignCriterionService.get(selector);
                    if (page.getEntries() != null) {
                        for (CampaignCriterion campaignCriterion : page.getEntries()) {
                            if (campaignCriterion.getCriterion().getCriterionType().equalsIgnoreCase(CriterionType.PROXIMITY.toString())) {
                                if (campaignCriterion.getCriterion() instanceof Proximity) {
                                    ProximityReport proximityReport = new ProximityReport();

                                    Proximity proximity = (Proximity) campaignCriterion.getCriterion();

                                    if (proximity.getAddress() != null) {
                                        proximityReport.AddressLine1 = proximity.getAddress().getStreetAddress();
                                        proximityReport.AddressLine2 = proximity.getAddress().getStreetAddress2();
                                        proximityReport.CampaignId = campaignCriterion.getCampaignId();
                                        proximityReport.CityName = proximity.getAddress().getCityName();
                                        proximityReport.CountryCode = proximity.getAddress().getCountryCode();
                                        proximityReport.PostalCode = proximity.getAddress().getPostalCode();
                                        proximityReport.ProvinceCode = proximity.getAddress().getProvinceCode();
                                        proximityReport.ProvinceName = proximity.getAddress().getProvinceName();
                                    }

                                    if (proximity.getGeoPoint() != null) {
                                        proximityReport.Latitude = proximity.getGeoPoint().getLatitudeInMicroDegrees();
                                        proximityReport.Longitude = proximity.getGeoPoint().getLongitudeInMicroDegrees();
                                    }

                                    proximityReport.CampaignId = campaignCriterion.getCampaignId();
                                    proximityReport.Id = proximity.getId();
                                    proximityReport.Radius = proximity.getRadiusInUnits();

                                    result.add(proximityReport);
                                }
                            }
                        }
                    }

                    offset += PAGE_SIZE;
                    selector.getPaging().setStartIndex(offset);

                } while (offset < page.getTotalNumEntries());


            } catch (Exception exc) {
                exc.printStackTrace(System.out);
            }
        } catch (Exception ex) {
            ex.printStackTrace(System.out);
        }

        return result;
    }

    protected ArrayList<LocationReport> GetLocations(String clientId){
        ArrayList<LocationReport> result = new ArrayList<LocationReport>();

        // Get the instance of service's factory
        ServiceFactory sf = ServiceFactory.getInstance();

        try {
            // Get Campaign Criterion Service
            CampaignCriterionServiceInterface campaignCriterionService = sf.GetCampaignCriterionService(clientId);

            int offset = 0;
            Selector selector = new Selector();

            selector.setPaging(new Paging(offset, PAGE_SIZE));
            //selector.setOrdering(new OrderBy[] {new OrderBy("Name", SortOrder.ASCENDING)});

            selector.setFields(new String[]{
                    "DisplayType",
                    "Id",
                    "IsNegative",
                    "LocationName",
                    "ParentLocations",
                    "TargetingStatus"
            });

            // Create predicates.
            Predicate criterionTypePredicate =
                    new Predicate("CriteriaType", PredicateOperator.EQUALS, new String[]{"LOCATION"});
            selector.setPredicates(new Predicate[]{criterionTypePredicate});

            CampaignCriterionPage page = null;

            try {
                do {
                    page = campaignCriterionService.get(selector);
                    if (page.getEntries() != null) {
                        for (CampaignCriterion campaignCriterion : page.getEntries()) {
                            if (campaignCriterion.getCriterion() instanceof Location) {
                                LocationReport locationReport = new LocationReport();

                                Location location = (Location) campaignCriterion.getCriterion();

                                locationReport.CampaignId = campaignCriterion.getCampaignId();
                                locationReport.DisplayType = location.getDisplayType();
                                locationReport.Id = location.getId();
                                locationReport.IsNegative = campaignCriterion.getIsNegative();
                                locationReport.LocationName = location.getLocationName();

                                if (location.getTargetingStatus() == LocationTargetingStatus.ACTIVE) {
                                    locationReport.TargetingStatus = "A";
                                } else if (location.getTargetingStatus() == LocationTargetingStatus.OBSOLETE) {
                                    locationReport.TargetingStatus = "O";
                                } else if (location.getTargetingStatus() == LocationTargetingStatus.PHASING_OUT) {
                                    locationReport.TargetingStatus = "P";
                                }

                                if (location.getParentLocations() != null) {
                                    locationReport.ParentIds = new long[location.getParentLocations().length];
                                    for (int i = 0; i < location.getParentLocations().length; i++) {
                                        locationReport.ParentIds[i] = location.getParentLocations()[i].getId();
                                    }
                                }

                                result.add(locationReport);
                            }
                        }
                    }

                    offset += PAGE_SIZE;
                    selector.getPaging().setStartIndex(offset);

                } while (offset < page.getTotalNumEntries());


            } catch (Exception exc) {
                exc.printStackTrace(System.out);
            }
        } catch (Exception ex) {
            ex.printStackTrace(System.out);
        }

        return result;
    }

    protected ArrayList<KeywordReport> GetKeywords(String clientId, ArrayList<String> campaignsToFilterOut) {

        ArrayList<KeywordReport> result = new ArrayList<KeywordReport>();

        try {
            // Get the instance of service's factory
            ServiceFactory sf = ServiceFactory.getInstance();

            // Get Campaign Criterion Service
            CampaignCriterionServiceInterface campaignCriterionService = sf.GetCampaignCriterionService(clientId);


            int offset = 0;
            Selector selector = new Selector();

            selector.setPaging(new Paging(offset, PAGE_SIZE));
            //selector.setOrdering(new OrderBy[] {new OrderBy("Name", SortOrder.ASCENDING)});

            selector.setFields(new String[]{
                    "Id",
                    "KeywordMatchType",
                    "KeywordText"
            });

            if (!campaignsToFilterOut.isEmpty()) {
                Object[] campaignsToArray = campaignsToFilterOut.toArray();
                String[] campaigns = new String[campaignsToArray.length];
                for (int i=0; i<campaignsToArray.length; i++) {
                    campaigns[i] = (String)campaignsToArray[i];
                }
                Predicate predicate = new Predicate("CampaignId", PredicateOperator.NOT_IN, campaigns);
                Predicate[] predicates = new Predicate[]{predicate};
                selector.setPredicates(predicates);
            }

            CampaignCriterionPage page = null;

            do {

                page = campaignCriterionService.get(selector);

                if (page.getEntries() != null) {

                    for (CampaignCriterion campaignCriterion : page.getEntries()) {


                        if (campaignCriterion.getCampaignCriterionType().equalsIgnoreCase("NegativeCampaignCriterion")) {
                            if (campaignCriterion instanceof NegativeCampaignCriterion) {
                                NegativeCampaignCriterion ncc = (NegativeCampaignCriterion) campaignCriterion;
                                if (ncc.getCriterion() instanceof Keyword) {
                                    KeywordReport keywordReport = new KeywordReport();

                                    Keyword keyword = (Keyword) ncc.getCriterion();

                                    keywordReport.CampaignId = campaignCriterion.getCampaignId();
                                    keywordReport.Id = keyword.getId();
                                    keywordReport.KeywordText = keyword.getText();

                                    if (keyword.getMatchType() == KeywordMatchType.EXACT) {
                                        keywordReport.KeywordMatchType = "E";
                                    } else if (keyword.getMatchType() == KeywordMatchType.PHRASE) {
                                        keywordReport.KeywordMatchType = "P";
                                    } else if (keyword.getMatchType() == KeywordMatchType.BROAD) {
                                        keywordReport.KeywordMatchType = "B";
                                    }

                                    result.add(keywordReport);
                                }
                            }
                        }


                    }


                }


                offset += PAGE_SIZE;
                selector.getPaging().setStartIndex(offset);

            } while (offset < page.getTotalNumEntries());


        } catch (Exception exc) {
            exc.printStackTrace(System.out);
        }


        return result;


    }

    public ArrayList<CampaignAdScheduleReport> GetAdSchedules(String clientId, ArrayList<String> campaignsToFilterOut) {
        ArrayList<CampaignAdScheduleReport> result = new ArrayList<CampaignAdScheduleReport>();

        // Get the instance of service's factory
        ServiceFactory sf = ServiceFactory.getInstance();

        try {
            // Get Campaign Criterion Service
            CampaignCriterionServiceInterface campaignCriterionServiceInterface = sf.GetCampaignCriterionService(clientId);

            int offset = 0;

            // Create selector.
            Selector selector = new Selector();
            selector.setFields(new String[]{
                    "Id"
            });
            selector.setOrdering(new OrderBy[]{new OrderBy("CampaignId", SortOrder.ASCENDING)});
            selector.setPaging(new Paging(offset, PAGE_SIZE));

            if (!campaignsToFilterOut.isEmpty()) {
                Object[] campaignsToArray = campaignsToFilterOut.toArray();
                String[] campaigns = new String[campaignsToArray.length];
                for (int i=0; i<campaignsToArray.length; i++) {
                    campaigns[i] = (String)campaignsToArray[i];
                }
                Predicate predicate = new Predicate("CampaignId", PredicateOperator.NOT_IN, campaigns);
                Predicate[] predicates = new Predicate[]{predicate};
                selector.setPredicates(predicates);
            }

            // Create predicates.
        /*Predicate adGroupIdPredicate =
                new Predicate("AdGroupId", PredicateOperator.IN, new String[]{adGroupId.toString()});*/
            Predicate criteriaTypePredicate =
                    new Predicate("CriteriaType", PredicateOperator.EQUALS, new String[]{"AD_SCHEDULE"});
            selector.setPredicates(new Predicate[]{criteriaTypePredicate});

            CampaignCriterionPage page = null;

            do {

                page = campaignCriterionServiceInterface.get(selector);

                if (page.getEntries() != null && page.getEntries().length > 0) {
                    // Display results.
                    for (CampaignCriterion campaignCriterionResult : page.getEntries()) {
                        CampaignAdScheduleReport campaignAdScheduleReport = new CampaignAdScheduleReport();
                        campaignAdScheduleReport.CampaignId = campaignCriterionResult.getCampaignId();

                        if (campaignCriterionResult.getCriterion() instanceof AdSchedule) {
                            AdSchedule adSchedule = (AdSchedule) campaignCriterionResult.getCriterion();
                            campaignAdScheduleReport.Id = adSchedule.getId();
                            campaignAdScheduleReport.DayOfWeek = Util.dayOfWeekToString(adSchedule.getDayOfWeek());
                            campaignAdScheduleReport.EndHour = adSchedule.getEndHour();
                            campaignAdScheduleReport.EndMinute = Util.minuteOfHourToInteger(adSchedule.getEndMinute());
                            campaignAdScheduleReport.StartHour = adSchedule.getStartHour();
                            campaignAdScheduleReport.StartMinute = Util.minuteOfHourToInteger(adSchedule.getStartMinute());
                            result.add(campaignAdScheduleReport);
                        }
                    }
                }


                offset += PAGE_SIZE;
                selector.getPaging().setStartIndex(offset);

            } while (offset < page.getTotalNumEntries());


        } catch (Exception exc) {
            exc.printStackTrace(System.out);
        }

        return result;
    }
}
